﻿using ClientDemo.Models;
using ClientDemo.Utility;
using Consul;
using Interface;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;

namespace ClientDemo.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IUserService _iUserService = null;
        private static int iSeed = 0;

        public HomeController(ILogger<HomeController> logger, IUserService userService)
        {
            _logger = logger;
            this._iUserService = userService;
        }

        public IActionResult Index()
        {
            #region 单体架构
            //base.ViewBag.Users = this._iUserService.UserAll();
            #endregion

            #region 分布式
            string url = null;

            //string url = "http://127.0.0.1:5726/api/users/all";
            //string url = "http://127.0.0.1:5727/api/users/all";
            //string url = "http://127.0.0.1:5728/api/users/all";

            #region Nginx
            //只是负载，静态的，不能动态添加。不能检查服务健康
            //url = "http://127.0.0.1:8080/api/users/all";//只知道nginx地址
            #endregion

            #region Consul
            //Consul能提供的就只有服务的Ip:Port--DNS
            //1、负载均衡
            //2、服务注册与发现
            //3、健康检查
            url = "http://ServiceInstance/api/users/all";  //DNS域名解析

            ConsulClient client = new ConsulClient(c =>
            {
                c.Address = new Uri("http://127.0.0.1:8500/");
                c.Datacenter = "dc1";
            });
            var response = client.Agent.Services().Result.Response;
            //foreach (var item in response)
            //{
            //    Console.WriteLine("***************************************");
            //    Console.WriteLine(item.Key);
            //    var service = item.Value;
            //    Console.WriteLine($"{service.Address}--{service.Port}--{service.Service}");
            //    Console.WriteLine("***************************************");
            //}

            Uri uri = new Uri(url);
            string groupName = uri.Host;//ServiceInstance
            AgentService agentService = null;

            var serviceDictionary = response.Where(s => s.Value.Service.Equals(groupName, StringComparison.OrdinalIgnoreCase)).ToArray();//得到3个实例

            //直接取第一个实例
            //agentService = serviceDictionary.First().Value;

            //平均策略 多个实例，平均分配--随机即平均
            //agentService = serviceDictionary[new Random(DateTime.Now.Millisecond+iSeed++).Next(0, serviceDictionary.Length)].Value;

            //轮询策略 很僵化
            //agentService = serviceDictionary[iSeed++ % serviceDictionary.Length].Value;

            //权重策略 
            List<KeyValuePair<string, AgentService>> pairsList = new List<KeyValuePair<string, AgentService>>();
            foreach (var pair in serviceDictionary) 
            {
                int count = int.Parse(pair.Value.Tags?[0]);
                for(int i = 0; i < count; i++)
                {
                    pairsList.Add(pair);
                }
            }
            agentService = pairsList.ToArray()[new Random(iSeed++).Next(0, pairsList.Count())].Value;

            //赋值URL
            url = $"{uri.Scheme}://{agentService.Address}:{agentService.Port}{uri.PathAndQuery}";

            //总结
            //解决了什么问题：
            //  服务注册与发现、健康检查、自动下线、等于是服务的管理
            //  不管调用
            //遗留了什么问题：
            //  没有实现负载均衡策略、没有解决客户端和服务调用
            //  没有解决客户端和服务调用的复杂性问题
            #endregion
            #endregion

            string content = ApiHelper.InvokeApi(url);
            base.ViewBag.Users = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<User>>(content);

            Console.WriteLine($"This is {url} Invoke");
            return View();
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}
